package com.example.service;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 日志服务类
 * 
 * 职责：
 * 1. 统一管理所有日志记录操作
 * 2. 提供多种日志记录方式
 * 3. 确保日志格式统一
 * 4. 处理日志文件IO操作
 * 5. 统计和分析选择器使用情况
 * 
 * 功能模块：
 * 1. 文件日志记录
 *    - 支持追加模式写入
 *    - 自动添加时间戳
 *    - 异常处理和资源管理
 * 
 * 2. 选择器日志
 *    - 记录CSS选择器使用情况
 *    - 记录选择器匹配内容
 *    - 记录相关URL信息
 *    - 记录未匹配的选择器
 *    - 统计选择器匹配率
 *    - 对比不同页面的选择器
 *    - 记录未匹配选择器的出现次数和内容
 * 
 * 3. 登录日志
 *    - 记录登录页面访问
 *    - 记录页面标题信息
 *    - 记录登录状态变化
 * 
 * 4. 爬虫运行日志
 *    - 记录爬虫运行状态
 *    - 记录重要操作信息
 *    - 记录异常情况
 * 
 * 使用方式：
 * 1. 通过Spring依赖注入使用
 * 2. 调用相应方法记录不同类型日志
 * 3. 日志同时输出到控制台和文件
 */
@Service
public class LogService {
    private static final Logger logger = LoggerFactory.getLogger(LogService.class);
    private static final String LOG_DIR = "./logs";
    private static final String LOG_FILE = "unmatched_selectors.log";
    
    // 用于统计选择器出现次数
    private final Map<String, Integer> selectorCount = new ConcurrentHashMap<>();
    // 用于记录已记录过的选择器
    private final Set<String> recordedSelectors = new HashSet<>();
    
    public LogService() {
        createLogDirectory();
        createLogFile();
    }
    
    /**
     * 创建日志目录
     * 职责：
     * 1. 检查日志目录是否存在
     * 2. 如果不存在则创建
     * 3. 处理创建失败的情况
     */
    private void createLogDirectory() {
        File logDir = new File(LOG_DIR);
        if (!logDir.exists()) {
            if (!logDir.mkdirs()) {
                logger.error("无法创建日志目录: {}", LOG_DIR);
            }
        }
    }
    
    /**
     * 创建日志文件
     * 职责：
     * 1. 检查日志文件是否存在
     * 2. 如果不存在则创建
     * 3. 处理创建失败的情况
     */
    private void createLogFile() {
        File file = new File(LOG_DIR, LOG_FILE);
        if (!file.exists()) {
            try {
                if (!file.createNewFile()) {
                    logger.error("无法创建日志文件: {}", LOG_FILE);
                }
            } catch (IOException e) {
                logger.error("创建日志文件失败: {}", LOG_FILE);
            }
        }
    }
    
    /**
     * 记录选择器使用情况
     * 职责：
     * 1. 统计选择器出现次数
     * 2. 记录未匹配的选择器
     * 3. 获取选择器包裹的内容
     * 4. 写入日志文件
     * 
     * @param selector CSS选择器
     * @param content 选择器包裹的内容
     * @param url 页面URL
     * @param matched 是否匹配成功
     */
    public void logSelector(String selector, String content, String url, boolean matched) {
        // 只处理匹配失败的情况
        if (!matched) {
            // 更新选择器计数
            int count = selectorCount.getOrDefault(selector, 0) + 1;
            selectorCount.put(selector, count);
            
            // 如果选择器出现次数超过5次且未被记录过，记录内容
            if (count > 5 && !recordedSelectors.contains(selector)) {
                recordedSelectors.add(selector);
                
                // 如果内容为空，尝试从文档中获取内容
                if (content == null || content.trim().isEmpty()) {
                    try {
                        Document doc = Jsoup.connect(url).get();
                        Elements elements = doc.select(selector);
                        if (!elements.isEmpty()) {
                            content = elements.first().text();
                        } else {
                            // 如果选择器没有匹配到内容，记录整个页面的主要内容
                            content = doc.select("body").text();
                        }
                    } catch (IOException e) {
                        content = "无法获取内容: " + e.getMessage();
                    }
                }
                
                String logMessage = String.format("[%s] 选择器: %s (出现次数: %d)\nURL: %s\n内容: %s\n",
                    new Date(), selector, count, url, content);
                
                try (OutputStreamWriter writer = new OutputStreamWriter(
                    new FileOutputStream(LOG_DIR + "/" + LOG_FILE, true), StandardCharsets.UTF_8)) {
                    writer.write(logMessage);
                    writer.write("----------------------------------------\n");
                } catch (IOException e) {
                    logger.error("写入未匹配选择器日志失败: {}", e.getMessage());
                }
            }
        }
    }
    
    /**
     * 记录通用日志
     * 职责：
     * 1. 记录各种类型的日志信息
     * 2. 支持自定义日志文件名
     * 3. 自动添加时间戳
     * 
     * @param filename 日志文件名
     * @param message 日志消息
     */
    public void logToFile(String filename, String message) {
        try (OutputStreamWriter writer = new OutputStreamWriter(
            new FileOutputStream(LOG_DIR + "/" + filename, true), StandardCharsets.UTF_8)) {
            writer.write(String.format("[%s] %s\n", new Date(), message));
        } catch (IOException e) {
            logger.error("写入日志文件失败: {} - {}", filename, e.getMessage());
        }
    }
} 